home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / GrowBoxDock / Sources / NavigationServicesSupport.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-30  |  14.5 KB  |  567 lines

  1. /*
  2.     File:        NavigationServicesSupport.c
  3.  
  4.     Contains:    Code to support Navigation Services in SimpleText
  5.  
  6.     Version:    Mac OS X
  7.  
  8.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  9.                 ("Apple") in consideration of your agreement to the following terms, and your
  10.                 use, installation, modification or redistribution of this Apple software
  11.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  12.                 please do not use, install, modify or redistribute this Apple software.
  13.  
  14.                 In consideration of your agreement to abide by the following terms, and subject
  15.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  16.                 copyrights in this original Apple software (the "Apple Software"), to use,
  17.                 reproduce, modify and redistribute the Apple Software, with or without
  18.                 modifications, in source and/or binary forms; provided that if you redistribute
  19.                 the Apple Software in its entirety and without modifications, you must retain
  20.                 this notice and the following text and disclaimers in all such redistributions of
  21.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  22.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  23.                 Apple Software without specific prior written permission from Apple.  Except as
  24.                 expressly stated in this notice, no other rights or licenses, express or implied,
  25.                 are granted by Apple herein, including but not limited to any patent rights that
  26.                 may be infringed by your derivative works or by other works in which the Apple
  27.                 Software may be incorporated.
  28.  
  29.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  30.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  31.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  32.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  33.                 COMBINATION WITH YOUR PRODUCTS.
  34.  
  35.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  36.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  37.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  39.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  40.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  41.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42.  
  43.     Copyright © 1997-2001 Apple Computer, Inc., All Rights Reserved
  44. */
  45.  
  46. #include "NavigationServicesSupport.h"
  47. #if !defined(USE_UMBRELLA_HEADERS) || !USE_UMBRELLA_HEADERS
  48. #include <CodeFragments.h>
  49. #include <Finder.h>
  50. #include <Dialogs.h>
  51. #include <LowMem.h>
  52. //#include <string.h>
  53. #include <Processes.h>
  54. #endif
  55.  
  56. #ifndef nrequire
  57.     #define nrequire(CONDITION, LABEL) if (true) {if ((CONDITION)) goto LABEL; }
  58. #endif
  59. #ifndef require
  60. #define require(CONDITION, LABEL) if (true) {if (!(CONDITION)) goto LABEL; }
  61. #endif
  62.  
  63.  
  64. static NavDialogRef gOpenFileDialog = NULL;
  65.  
  66.  
  67. static pascal void MyEventProc( const NavEventCallbackMessage callbackSelector, 
  68.                                 NavCBRecPtr callbackParms, 
  69.                                 NavCallBackUserData callbackUD );
  70.  
  71.  
  72. static NavEventUPP GetEventUPP()
  73. {
  74.     static NavEventUPP    eventUPP = NULL;                
  75.     if ( eventUPP == NULL )
  76.     {
  77.         eventUPP = NewNavEventUPP( MyEventProc );
  78.     }
  79.     return eventUPP;
  80. }
  81.  
  82.  
  83. static pascal void MyPrivateEventProc( const NavEventCallbackMessage callbackSelector, 
  84.                                        NavCBRecPtr callbackParms, 
  85.                                        NavCallBackUserData callbackUD );
  86.  
  87.  
  88. static NavEventUPP GetPrivateEventUPP()
  89. {
  90.     static NavEventUPP    privateEventUPP = NULL;                
  91.     if ( privateEventUPP == NULL )
  92.     {
  93.         privateEventUPP = NewNavEventUPP( MyPrivateEventProc );
  94.     }
  95.     return privateEventUPP;
  96. }
  97.  
  98.  
  99. static Handle NewOpenHandle(OSType applicationSignature, short numTypes, OSType typeList[])
  100. {
  101.     Handle hdl = NULL;
  102.     
  103.     if ( numTypes > 0 )
  104.     {
  105.     
  106.         hdl = NewHandle(sizeof(NavTypeList) + numTypes * sizeof(OSType));
  107.     
  108.         if ( hdl != NULL )
  109.         {
  110.             NavTypeListHandle open        = (NavTypeListHandle)hdl;
  111.             
  112.             (*open)->componentSignature = applicationSignature;
  113.             (*open)->osTypeCount        = numTypes;
  114.             BlockMoveData(typeList, (*open)->osType, numTypes * sizeof(OSType));
  115.         }
  116.     }
  117.     
  118.     return hdl;
  119. }
  120.  
  121.  
  122. OSStatus SendOpenAE( AEDescList list )
  123. {
  124.     OSStatus        err;
  125.     AEAddressDesc    theAddress;
  126.     AppleEvent        dummyReply;
  127.     AppleEvent        theEvent;
  128.     
  129.     theAddress.descriptorType    = typeNull;
  130.     theAddress.dataHandle        = NULL;
  131.  
  132.     dummyReply.descriptorType    = typeNull;
  133.     dummyReply.dataHandle        = NULL;
  134.  
  135.     theEvent.descriptorType        = typeNull;
  136.     theEvent.dataHandle            = NULL;
  137.  
  138.     do {
  139.         ProcessSerialNumber psn;
  140.  
  141.         err = GetCurrentProcess(&psn);
  142.         if ( err != noErr) break;
  143.         
  144.         err =AECreateDesc(typeProcessSerialNumber, &psn, sizeof(ProcessSerialNumber), &theAddress);
  145.         if ( err != noErr) break;
  146.  
  147.         err = AECreateAppleEvent(kCoreEventClass, kAEOpenDocuments, &theAddress, kAutoGenerateReturnID, kAnyTransactionID, &theEvent);
  148.         if ( err != noErr) break;
  149.         
  150.         err = AEPutParamDesc(&theEvent, keyDirectObject, &list);
  151.         if ( err != noErr) break;
  152.         
  153.         err = AESend(&theEvent, &dummyReply, kAENoReply, kAENormalPriority, kAEDefaultTimeout, NULL, NULL);
  154.         if ( err != noErr) break;
  155.         
  156.         
  157.     } while (false);
  158.     
  159.     if ( theAddress.dataHandle != NULL )
  160.     {
  161.         AEDisposeDesc( &theAddress );
  162.     }
  163.  
  164.     if ( dummyReply.dataHandle != NULL )
  165.     {
  166.         AEDisposeDesc( &dummyReply );
  167.     }
  168.  
  169.     if ( theEvent.dataHandle != NULL )
  170.     {
  171.         AEDisposeDesc( &theEvent );
  172.     }
  173.  
  174.     return err;
  175. }
  176.  
  177.  
  178. OSStatus OpenFileDialog(
  179.     OSType applicationSignature, 
  180.     short numTypes, 
  181.     OSType typeList[], 
  182.     NavDialogRef *outDialog )
  183. {
  184.     OSStatus theErr = noErr;
  185.     if ( gOpenFileDialog == NULL )
  186.     {
  187.         NavDialogCreationOptions    dialogOptions;
  188.         NavTypeListHandle            openList    = NULL;
  189.     
  190.         NavGetDefaultDialogCreationOptions( &dialogOptions );
  191.     
  192.         dialogOptions.modality = kWindowModalityNone;
  193.         dialogOptions.clientName = CFStringCreateWithPascalString( NULL, LMGetCurApName(), CFStringGetSystemEncoding());
  194.         
  195.         openList = (NavTypeListHandle)NewOpenHandle( applicationSignature, numTypes, typeList );
  196.         
  197.         theErr = NavCreateGetFileDialog( &dialogOptions, openList, GetPrivateEventUPP(), NULL, NULL, NULL, &gOpenFileDialog );
  198.  
  199.         if ( theErr == noErr )
  200.         {
  201.             theErr = NavDialogRun( gOpenFileDialog );
  202.             if ( theErr != noErr )
  203.             {
  204.                 NavDialogDispose( gOpenFileDialog );
  205.                 gOpenFileDialog = NULL;
  206.             }
  207.         }
  208.  
  209.         if (openList != NULL)
  210.         {
  211.             DisposeHandle((Handle)openList);
  212.         }
  213.         
  214.         if ( dialogOptions.clientName != NULL )
  215.         {
  216.             CFRelease( dialogOptions.clientName );
  217.         }
  218.     }
  219.     else
  220.     {
  221.         if ( NavDialogGetWindow( gOpenFileDialog ) != NULL )
  222.         {
  223.             SelectWindow( NavDialogGetWindow( gOpenFileDialog ));
  224.         }
  225.     }
  226.     
  227.     if ( outDialog != NULL )
  228.     {
  229.         *outDialog = gOpenFileDialog;
  230.     }
  231.  
  232.     return NULL;
  233. }
  234.  
  235.  
  236. void TerminateOpenFileDialog()
  237. {
  238.     if ( gOpenFileDialog != NULL )
  239.     {
  240.         TerminateDialog( gOpenFileDialog );
  241.     }
  242. }
  243.  
  244.  
  245. void TerminateDialog( NavDialogRef inDialog )
  246. {
  247.     NavCustomControl( inDialog, kNavCtlTerminate, NULL );
  248. }
  249.  
  250.  
  251. static OSStatus UniversalConfirmSaveDialog(
  252.     WindowRef parentWindow, 
  253.     ConstStringPtr documentName, 
  254.     Boolean quitting, 
  255.     void* inContextData,
  256.     NavDialogRef *outDialog,
  257.     NavUserAction *outUserAction )
  258. {
  259.     OSStatus                     theErr             = noErr;
  260.     NavAskSaveChangesAction        action             = 0;
  261.     NavDialogRef                dialog             = NULL;
  262.     NavUserAction                userAction         = kNavUserActionNone;
  263.     NavDialogCreationOptions    dialogOptions;
  264.     NavEventUPP                    eventUPP;
  265.     Boolean                        disposeAfterRun;
  266.  
  267.     NavGetDefaultDialogCreationOptions( &dialogOptions );
  268.  
  269.     action = quitting ? kNavSaveChangesQuittingApplication : kNavSaveChangesClosingDocument;
  270.     dialogOptions.modality = ( parentWindow != NULL ) ? kWindowModalityWindowModal : kWindowModalityAppModal;
  271.     dialogOptions.parentWindow = parentWindow;
  272.  
  273.     dialogOptions.clientName = CFStringCreateWithPascalString( NULL, LMGetCurApName(), CFStringGetSystemEncoding());
  274.     if ( documentName != NULL )
  275.     {
  276.         dialogOptions.saveFileName = CFStringCreateWithPascalString( NULL, documentName, CFStringGetSystemEncoding());
  277.     }
  278.  
  279.     eventUPP = ( inContextData == NULL ) ? GetPrivateEventUPP() : GetEventUPP();
  280.     disposeAfterRun = ( dialogOptions.modality == kWindowModalityAppModal && inContextData == NULL );
  281.  
  282.     theErr = NavCreateAskSaveChangesDialog(    
  283.                 &dialogOptions,
  284.                 action,
  285.                 eventUPP,
  286.                 inContextData,
  287.                 &dialog );
  288.     
  289.     if ( theErr == noErr )
  290.     {
  291.         theErr = NavDialogRun( dialog );
  292.         if ( theErr != noErr || disposeAfterRun )
  293.         {
  294.             userAction = NavDialogGetUserAction( dialog );
  295.             NavDialogDispose( dialog );
  296.             dialog = NULL;
  297.         }
  298.     }
  299.  
  300.     if ( dialogOptions.clientName != NULL )
  301.     {
  302.         CFRelease( dialogOptions.clientName );
  303.     }
  304.     if ( dialogOptions.saveFileName != NULL )
  305.     {
  306.         CFRelease( dialogOptions.saveFileName );
  307.     }
  308.     if ( outDialog != NULL )
  309.     {
  310.         *outDialog = dialog;
  311.     }
  312.     if ( outUserAction != NULL )
  313.     {
  314.         *outUserAction = userAction;
  315.     }
  316.     return theErr;
  317. }
  318.  
  319.  
  320. OSStatus ConfirmSaveDialog(
  321.     WindowRef parentWindow, 
  322.     ConstStringPtr documentName, 
  323.     Boolean quitting, 
  324.     void* inContextData,
  325.     NavDialogRef *outDialog )
  326. {
  327.     return UniversalConfirmSaveDialog( parentWindow, documentName, quitting, inContextData, outDialog, NULL );
  328. }
  329.  
  330.  
  331. OSStatus ModalConfirmSaveDialog(
  332.     ConstStringPtr documentName, 
  333.     Boolean quitting, 
  334.     NavUserAction *outUserAction )
  335. {
  336.     return UniversalConfirmSaveDialog( NULL, documentName, quitting, NULL, NULL, outUserAction );
  337. }
  338.  
  339.  
  340. OSStatus SaveFileDialog(
  341.     WindowRef parentWindow, 
  342.     StringPtr documentName, 
  343.     OSType filetype, 
  344.     OSType fileCreator, 
  345.     void *inContextData,
  346.     NavDialogRef *outDialog )
  347. {
  348.     NavDialogCreationOptions    dialogOptions;
  349.     OSStatus                    theErr = noErr;
  350.  
  351.     NavGetDefaultDialogCreationOptions( &dialogOptions );
  352.  
  353.     dialogOptions.clientName = CFStringCreateWithPascalString( NULL, LMGetCurApName(), CFStringGetSystemEncoding());
  354.     dialogOptions.saveFileName = CFStringCreateWithPascalString( NULL, documentName, CFStringGetSystemEncoding());
  355.     dialogOptions.modality = ( parentWindow != NULL ) ? kWindowModalityWindowModal : kWindowModalityAppModal;
  356.     dialogOptions.parentWindow = parentWindow;
  357.  
  358.     theErr = NavCreatePutFileDialog( &dialogOptions, filetype, fileCreator, GetEventUPP(), inContextData, outDialog );
  359.     
  360.     if ( theErr == noErr )
  361.     {
  362.         theErr = NavDialogRun( *outDialog );
  363.         if ( theErr != noErr )
  364.         {
  365.             NavDialogDispose( *outDialog );
  366.         }
  367.         if ( theErr != noErr || dialogOptions.modality == kWindowModalityAppModal )
  368.         {
  369.             *outDialog = NULL;    // The dialog has already been disposed.
  370.         }
  371.     }
  372.  
  373.     if ( dialogOptions.clientName != NULL )
  374.     {
  375.         CFRelease( dialogOptions.clientName );
  376.     }
  377.     if ( dialogOptions.saveFileName != NULL )
  378.     {
  379.         CFRelease( dialogOptions.saveFileName );
  380.     }
  381.  
  382.     return theErr;
  383. }
  384.  
  385.  
  386. OSStatus BeginSave( NavDialogRef inDialog, NavReplyRecord* outReply, FSSpec* outFileSpec )
  387. {
  388.     OSStatus status = paramErr;
  389.     AEDesc        dirDesc;
  390.     AEKeyword    keyword;
  391.     CFIndex        len;
  392.  
  393.     require( outReply, Return );
  394.     require( outFileSpec, Return );
  395.  
  396.     status = NavDialogGetReply( inDialog, outReply );
  397.     nrequire( status, Return );
  398.     
  399.     status = AEGetNthDesc( &outReply->selection, 1, typeWildCard, &keyword, &dirDesc );
  400.     nrequire( status, DisposeReply );
  401.     
  402.     len = CFStringGetLength( outReply->saveFileName );
  403.  
  404.     if ( dirDesc.descriptorType == typeFSRef )
  405.     {
  406.         const UInt32    kMaxNameLen = 255;
  407.         FSRef            dirRef;
  408.         UniChar            name[ kMaxNameLen ];
  409.  
  410.         if ( len > kMaxNameLen )
  411.         {
  412.             len = kMaxNameLen;
  413.         }
  414.     
  415.         status = AEGetDescData( &dirDesc, &dirRef, sizeof( dirRef ));
  416.         nrequire( status, DisposeDesc );
  417.         
  418.         CFStringGetCharacters( outReply->saveFileName, CFRangeMake( 0, len ), &name[0] );
  419.         
  420.         status = FSCreateFileUnicode( &dirRef, len, &name[0], 0, NULL, NULL, outFileSpec );
  421.         nrequire( status, DisposeDesc );
  422.     }
  423.     else if ( dirDesc.descriptorType == typeFSS )
  424.     {
  425.         status = AEGetDescData( &dirDesc, outFileSpec, sizeof( FSSpec ));
  426.         nrequire( status, DisposeDesc );
  427.  
  428.         if ( CFStringGetPascalString( outReply->saveFileName, &(outFileSpec->name[0]), 
  429.                     sizeof( StrFileName ), CFStringGetSystemEncoding()))
  430.         {
  431.             status = FSpCreate( outFileSpec, 0, 0, smSystemScript );
  432.             nrequire( status, DisposeDesc );
  433.         }
  434.         else
  435.         {
  436.             status = bdNamErr;
  437.             nrequire( status, DisposeDesc );
  438.         }
  439.     }
  440.  
  441. DisposeDesc:
  442.     AEDisposeDesc( &dirDesc );
  443.  
  444. DisposeReply:
  445.     if ( status != noErr )
  446.     {
  447.         NavDisposeReply( outReply );
  448.     }
  449.  
  450. Return:
  451.     return status;
  452. }
  453.  
  454.  
  455. OSStatus CompleteSave( NavReplyRecord* inReply, FSSpec* inFileSpec, Boolean inDidWriteFile )
  456. {
  457.     OSStatus theErr;
  458.     
  459.     if ( inReply->validRecord )
  460.     {
  461.         if ( inDidWriteFile )
  462.         {
  463.             theErr = NavCompleteSave( inReply, kNavTranslateInPlace );
  464.         }
  465.         else if ( !inReply->replacing )
  466.         {
  467.             // Write failed, not replacing, so delete the file
  468.             // that was created in BeginSave.
  469.             FSpDelete( inFileSpec );
  470.         }
  471.  
  472.         theErr = NavDisposeReply( inReply );
  473.     }
  474.  
  475.     return theErr;
  476. }
  477.  
  478.  
  479. //
  480. // Callback to handle events that occur while navigation dialogs are up but really should be handled by the application
  481. //
  482.  
  483. extern void HandleEvent( EventRecord * pEvent );
  484. extern void HandleNavUserAction( NavDialogRef inNavDialog, NavUserAction inUserAction, void* inContextData );
  485.  
  486. static pascal void MyEventProc( const NavEventCallbackMessage callbackSelector, 
  487.                                 NavCBRecPtr callbackParms, 
  488.                                 NavCallBackUserData callbackUD )
  489. // Callback to handle event passing betwwn the navigation dialogs and the applicatio
  490. {
  491.     switch ( callbackSelector )
  492.     {    
  493.         case kNavCBEvent:
  494.         {
  495.             switch (callbackParms->eventData.eventDataParms.event->what)
  496.             {
  497.                 case updateEvt:
  498.                 case activateEvt:
  499.                     HandleEvent(callbackParms->eventData.eventDataParms.event);
  500.                 break;
  501.             }
  502.         }
  503.         break;
  504.  
  505.         case kNavCBUserAction:
  506.         {
  507.             // Call HandleNavUserAction
  508.             HandleNavUserAction( callbackParms->context, callbackParms->userAction, callbackUD );
  509.         }
  510.         break;
  511.         
  512.         case kNavCBTerminate:
  513.         {
  514.             // Auto-dispose the dialog
  515.             NavDialogDispose( callbackParms->context );
  516.         }
  517.     }
  518. }
  519.  
  520. static pascal void MyPrivateEventProc( const NavEventCallbackMessage callbackSelector, 
  521.                                        NavCBRecPtr callbackParms, 
  522.                                        NavCallBackUserData callbackUD )
  523. {
  524.     switch ( callbackSelector )
  525.     {    
  526.         case kNavCBEvent:
  527.         {
  528.             switch (callbackParms->eventData.eventDataParms.event->what)
  529.             {
  530.                 case updateEvt:
  531.                 case activateEvt:
  532.                     HandleEvent(callbackParms->eventData.eventDataParms.event);
  533.                 break;
  534.             }
  535.         }
  536.         break;
  537.  
  538.         case kNavCBUserAction:
  539.         {
  540.             if ( callbackParms->userAction == kNavUserActionOpen )
  541.             {
  542.                 // This is an open files action, send an AppleEvent
  543.                 NavReplyRecord    reply;
  544.                 OSStatus        status;
  545.                 
  546.                 status = NavDialogGetReply( callbackParms->context, &reply );
  547.                 if ( status == noErr )
  548.                 {
  549.                     SendOpenAE( reply.selection );
  550.                     NavDisposeReply( &reply );
  551.                 }
  552.             }
  553.         }
  554.         break;
  555.         
  556.         case kNavCBTerminate:
  557.         {
  558.             if ( callbackParms->context == gOpenFileDialog )
  559.             {
  560.                 NavDialogDispose( gOpenFileDialog );
  561.                 gOpenFileDialog = NULL;
  562.             }
  563.         }
  564.         break;
  565.     }
  566. }
  567.